﻿using CofeCore = Cofe.Core;
using CofeIO = Cofe.IO;
using Cofe.Core.Implements;
using Cofe.Core.Property;
using Cofe.IO.Interfaces;
using Cofe.Core.Utils;
using Cofe.IO.Implements;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
#if NETFX_CORE
using Windows.Storage;
using Cofe.Core;
using Windows.Storage.Streams;
using Cofe.Core.Logger;
#endif


namespace Cofe.IO.Implements
{

#if NETFX_CORE
    public class WindowsStoragePropertyProvider : PropertyProviderBase<IStorageItem>, IFSIPropertyProvider
    {
        #region Constructor
        public WindowsStoragePropertyProvider(WindowsStorageDirectoryLister directoryLister, IStorageItem entry)
            : base(entry,
            entry.IsOfType(StorageItemTypes.Folder) ?
            new IPropertyDefinitions[] { 
                CofeCore.PropertyDefinitions.CofeDefinitions, 
                CofeCore.PropertyDefinitions.CofeDirDefinitions, 
                CofeIO.PropertyDefinitions.FSIPropDefinitions, 
                CofeIO.PropertyDefinitions.DIPropDefinitions 
            } :
            new IPropertyDefinitions[] { 
                CofeCore.PropertyDefinitions.CofeDefinitions, 
                CofeCore.PropertyDefinitions.CofeFileDefinitions, 
                CofeCore.PropertyDefinitions.CofeStreamDefinitions,
                CofeIO.PropertyDefinitions.FSIPropDefinitions, 
                CofeIO.PropertyDefinitions.FIPropDefinitions })
        {
            _dirLister = directoryLister;
            var volumeInfo = directoryLister.Volume;

            if (!entry.Path.StartsWith(directoryLister.VolumePath))
                throw new Exception("");

            _parseName = PathFE.FormatFullParseName(volumeInfo.VolumeId, entry.Path
                    .Replace(directoryLister.VolumePath, "", StringComparison.OrdinalIgnoreCase)).TrimEnd('\\');
            _parentParseName = PathFE.GetDirectoryName(_parseName);

            _isFile = Entity is IStorageFile;
            _isFolder = !_isFile;

            registerProperties(CofeProperties.DefaultInterfaceType, () =>
                   _isFile ? typeof(IFileInfo) : typeof(IDirectoryInfo));
            registerProperties(CofeProperties.Type, () => _isFile ? FileTypes.File : FileTypes.Folder);
            registerProperties(CofeProperties.Label, () => Entity.Name);

            registerProperties(CofeProperties.IsExists, () => true);
            registerProperties(FileSystemInfoProperties.FileAttributes, () => (Cofe.IO.FileAttributes)(int)Entity.Attributes);
            registerProperties(CofeProperties.CofeAttributes, () =>
                {
                    return (_isFolder) ?
                        CofeAttributes.FileSystem | CofeAttributes.SubEntriesCanChange | CofeAttributes.Browsable :
                        CofeAttributes.FileSystem;
                }
            );

            //registerProperties(CofeProperties.LastWriteTimeUtc, () => Entity.LastWriteTimeUtc,
            //    (pp) => { Entity.LastWriteTimeUtc = pp.ValueAsUtcDateTime; return true; });
            registerProperties(CofeProperties.CreationTimeUtc, () => Entity.DateCreated);

            registerProperties(CofeProperties.FullParseName, () => _parseName);
            registerProperties(CofeProperties.ParentParseName, () => _parentParseName ?? null);

            registerProperties(FileSystemInfoProperties.FullName, () => Entity.Path);

            registerActionAsync(CofeProperties.DeleteAsync, (pm) => Task.Run(async () =>
            { await Entity.DeleteAsync(); pm.IsHandled = true; }));

            if (_isFile)
            {
                registerProperties(CofeItemProperties.Length, () => { return (Entity as IStorageFile).GetBasicPropertiesAsync().GetResults().Size; });
                registerActionAsync(CofeStreamProperties.OpenReadAsync,
                 (pm) => Task.Run<StreamContainer>(async () => StreamContainer.FromInputStream(await FileEntity.OpenAsync(FileAccessMode.Read), _parseName)));
                registerActionAsync(CofeStreamProperties.OpenWriteAsync,
                 (pm) => Task.Run<StreamContainer>(async () => StreamContainer.FromRandomAccessStream(await FileEntity.OpenAsync(FileAccessMode.ReadWrite), _parseName)));
                registerActionAsync(CofeStreamProperties.OpenReadWriteAsync,
                 (pm) => Task.Run<StreamContainer>(async () => StreamContainer.FromRandomAccessStream(await FileEntity.OpenAsync(FileAccessMode.ReadWrite), _parseName)));


            }

            if (_isFolder)
            {
                Func<ParameterDic, Task<IEnumerable<IPropertyProvider>>>
                    asyncList = (pm) => Task.Run<IEnumerable<IPropertyProvider>>(() => { pm.IsHandled = true; return listAsync(); });
                registerProperties(CofeDirectoryProperties.ListCoreAsync, () => asyncList);

                registerActionAsync(CofeDirectoryProperties.CreateAsync, (pm) => create(pm));

                //registerProperties(CofeDirectoryProperties.DirectoryType, () =>
                //    {
                //        if (Entity.FullName.Equals(volumeInfo.VolumePath)) return DirectoryTypeEnum.dtVolume;
                //        return Entity.FullName.EndsWith(":\\") ? DirectoryTypeEnum.dtRoot : DirectoryTypeEnum.dtFolder;
                //    }
                //        );
                //registerProperties(CofeDirectoryProperties.IsFileBasedFS, () => false);
            }
        }

        #endregion

        #region Methods

        private async Task<IEnumerable<IPropertyProvider>> listAsync()
        {
            CofeServices.Logger.Log("SystemIO listing {0}", _parseName);
            var subItems = await DirEntity.GetItemsAsync();
            return new List<IPropertyProvider>(
               from i in subItems
               select new WindowsStoragePropertyProvider(_dirLister, i));
            CofeServices.Logger.Log("SystemIO listed {0}", _parseName);
        }

        private async Task<IPropertyProvider> create(ParameterDic dic)
        {

            string type = dic.ContainsKey("Type") ? (string)dic["Type"] : null;
            string name = dic.ContainsKey("Name") ? (string)dic["Name"] : null;
            if (string.IsNullOrEmpty(type) || string.IsNullOrEmpty(name))
                return null;
            string destName = PathFE.Combine(Entity.Path, name);

            switch (type.ToLower())
            {
                case "folder":
                case "directory":
                    try
                    {
                        IStorageItem createdFolder = (await DirEntity.GetFoldersAsync())
                            .FirstOrDefault(f => f.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase));                        
                        if (createdFolder == null)
                            createdFolder = await DirEntity.CreateFolderAsync(name);
                        dic.IsHandled = true;
                        ManualEventSource.NotifyCreated(PathFE.Combine(_parseName, name), true);
                        return new WindowsStoragePropertyProvider(_dirLister, createdFolder);
                    }
                    catch (Exception ex)
                    {
                        dic.Error = ex;
                        return null;
                    }
                case "file":
                    try
                    {
                        IStorageItem createdFile = (await DirEntity.GetFilesAsync())
                            .FirstOrDefault(f => f.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase));
                        if (createdFile == null)
                            createdFile = await DirEntity.CreateFileAsync(name);

                        dic.IsHandled = true;
                        ManualEventSource.NotifyCreated(PathFE.Combine(_parseName, name), true);
                        return new WindowsStoragePropertyProvider(_dirLister, createdFile);
                    }
                    catch (Exception ex)
                    {
                        dic.Error = ex;
                        return null;
                    }
                default:
                    return null;
            }
        }

        #endregion

    #region Data

        private WindowsStorageDirectoryLister _dirLister;
        private string _parseName, _parentParseName;
        private bool _isFile, _isFolder;

    #endregion

    #region Public Properties

        public IManualCofeSystemEventSource ManualEventSource { get; set; }

        public IStorageFolder DirEntity { get { return Entity as IStorageFolder; } }
        public IStorageFile FileEntity { get { return Entity as IStorageFile; } }


    #endregion
    }





#endif
}
